#include <func.h>

int main(int argc, char *argv[])
{
    ARGS_CHECK(argc, 3);

    // 1. 生成套接字描述符
    int sfd = socket(AF_INET, SOCK_STREAM, 0);

    // 让端口号在经历TIME_WAIT时可重用
    int reuse = 1;
    int ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
    ERROR_CHECK(ret, -1, "setsockopt");

    // 2. bind
    struct sockaddr_in ser_addr; // 服务器信息结构体
    bzero(&ser_addr, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET; // 使用IPv4
    ser_addr.sin_port = htons(atoi(argv[2])); // 端口号
    ser_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP地址

    
    ret = bind(sfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
    ERROR_CHECK(ret, -1, "bind");

    // 3. listen
    ret = listen(sfd, 10);

    // 4. accept 进行三次握手
    struct sockaddr_in client_addr; // 客户端信息结构体
    bzero(&client_addr, sizeof(client_addr));
    socklen_t addr_len = sizeof(client_addr);
    // 实际用来和客户端通信的标识符
    int new_fd = accept(sfd, (struct sockaddr *)&client_addr, &addr_len);
    ERROR_CHECK(new_fd, -1, "accept");
    printf("client %s %d success connect\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

    // epoll实现实时聊天
    char buf[128] = {0};
    int epfd = epoll_create(1);
    struct epoll_event event, evs[2];

    // 先注册标准输入
    event.data.fd = STDIN_FILENO;
    event.events = EPOLLIN;
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);

    // 再注册new_fd
    event.data.fd = new_fd;
    event.events = EPOLLIN;
    epoll_ctl(epfd, EPOLL_CTL_ADD, new_fd, &event);
    
    while (1)
    {
        // 返回就绪的number
        int ready_fd_num = epoll_wait(epfd, evs, 2, -1);
        for (int i = 0; i < ready_fd_num; i ++)
        {
            // 可发
            if (evs[i].data.fd == STDIN_FILENO)
            {
                bzero(buf, sizeof(buf));
                read(STDIN_FILENO, buf, sizeof(buf));
                send(new_fd, buf, strlen(buf) - 1, 0);
            }

            // 可收
            if (evs[i].data.fd == new_fd)
            {
                bzero(buf, sizeof(buf));
                ret = recv(new_fd, buf, sizeof(buf), 0);
                if (!ret) 
                {
                    printf("The server break the connect\n");
                    return 0;
                }
                printf("%s\n", buf);
            }
        }
        
    }

    close(sfd);
    close(new_fd);
    return 0;
}
